/*
 * SimpleNetwLayer.h
 *
 *  Created on: 29.08.2008
 *      Author: Karl Wessel
 */

#ifndef SIMPLENETWLAYER_H_
#define SIMPLENETWLAYER_H_

#include <omnetpp.h>
#include <cassert>
#include <BaseModule.h>
#include <NetwPkt_m.h>
#include <SimpleAddress.h>
#include <NetwToMacControlInfo.h>
#include <MacToNetwControlInfo.h>
#include <BaseMacLayer.h>

/**
 * @brief This is an implementation of a simple network layer
 * which provides only some simple routing (next hop) and
 * message forwarding (only switches).
 *
 * This network layer isn't a real network layer its only purpose
 * is to provide some message sending for the CSMA-Mac layer.
 *
 * At first there is a small "saying hello"-phase where the
 * several network layers saying hello to each other and creating
 * their routing table.
 *
 * After that phase the non-switch instances start to babbling randomly
 * to other instances without caring if they here them.
 * The switch instances does only provide packet forwarding from there on.
 *
 * The several instances can babble directly to each other or over
 * a switch instance.
 *
 * @ingroup exampleCSMA
 */
class BmacNetwLayer : public BaseModule{
//--------members----------
protected:
	/** @brief time after when the module gets bored and starts jabbering. */
	simtime_t boredTime;

	int maxTtl;

	int ip;

	int dataIn;
	int dataOut;

	cMessage* startJabberTimer;
	cMessage* helloWorldTimer;

	unsigned long runningSeqNumber;

	typedef std::map<int, int> RoutingTable;

	RoutingTable routingTable;

	enum TimerKind{
		TIMERHELLOWORLD = 1000,
	};

	enum NetwPktKind{
		HELLO_WORLD = 4200,
		JABBER,
		START_TO_JABBER
	};

	long SendedSensorData;
	long ReceivedSensorData;

//--------methods----------
protected:
	void scheduleJabbering(){
		if(startJabberTimer->isScheduled()){
			cancelEvent(startJabberTimer);
		}
		scheduleAt(simTime() + boredTime*dblrand()+2, startJabberTimer);
	}

	void sendDown(cPacket* pkt) {
			send(pkt, dataOut);
	}

	void SendForward(NetwPkt* pkt){
		NetwPkt* fwd = new NetwPkt(pkt->getName(), pkt->getKind());

		fwd->setDestAddr(pkt->getDestAddr());
		fwd->setSrcAddr(pkt->getSrcAddr());
		fwd->setSeqNum(pkt->getSeqNum());
		fwd->setTtl(ip);
		NetwToMacControlInfo* cInfo = new NetwToMacControlInfo(ip);
		fwd->setControlInfo(cInfo);
		sendDown(fwd);
	}


	void jabberToNode0()
	{
		NetwPkt* SensorData = new NetwPkt("SensorData", JABBER);

		SensorData->setDestAddr(0);
		SensorData->setSrcAddr(ip);
		SensorData->setSeqNum(runningSeqNumber++);
		SensorData->setTtl(ip);
		NetwToMacControlInfo* cInfo = new NetwToMacControlInfo(ip);
		SensorData->setControlInfo(cInfo);
		getNode()->bubble("SensorData");
		sendDown(SensorData);
		SendedSensorData++;

	}

	void handleIncomingJabber(NetwPkt* pkt)
	{
		if(pkt->getSrcAddr() == ip){
			delete pkt;
			return;
		}
		switch(ip){
		case 0:
			if (1 != (pkt->getTtl() - ip)){
							delete pkt;
							return;
			}else{
				EV<<"Receive a SensorData from Node " <<pkt->getSrcAddr()<<endl;
				ReceivedSensorData ++ ;
			}
			break;
		default:
			if (1 != (pkt->getTtl() - ip)){
				delete pkt;
				return;
			}else{
			 SendForward(pkt);
			}

		}
	}


public:
	virtual ~BmacNetwLayer() {

	}

	void finish() {
		recordScalar("SendedSensorData", SendedSensorData);
		recordScalar("ReceivedSensorData", ReceivedSensorData);
	}

	virtual void initialize(int stage){

		if(stage == 0){
			dataOut = findGate("lowerGateOut");
			dataIn = findGate("lowerGateIn");
			ip = par("ip").longValue();
			maxTtl = par("maxTtl").longValue();
			boredTime = par("boredTime").doubleValue();
		} else if(stage == 1) {

			SendedSensorData = 0;
			ReceivedSensorData = 0;
			if(ip != 0){
			startJabberTimer = new cMessage("jabber!", START_TO_JABBER);
			scheduleJabbering();
			}
		}
	}

	virtual void handleMessage(cMessage* msg){

		switch(msg->getKind()){
		case START_TO_JABBER:
			// 10% that send sensor data
			if(dblrand()<0.1)
				jabberToNode0();
			scheduleJabbering();
			break;
		case JABBER:
			handleIncomingJabber(static_cast<NetwPkt*>(msg));
			break;

		case BaseMacLayer::PACKET_DROPPED:
			ev << "Packet dropped by MAC layer." << endl;
			delete msg;
			break;

		default:
			error("unknown packet type of packet %s", msg->getName());
			break;
		}
	}

};

#endif /* SIMPLENETWLAYER_H_ */
